home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / x / volume0 / awm / part12 < prev    next >
Encoding:
Text File  |  1988-08-12  |  41.6 KB  |  1,485 lines

  1. Path: uunet!wyse!mikew
  2. From: mikew@wyse.wyse.com (Mike Wexler)
  3. Newsgroups: comp.sources.x
  4. Subject: v00i013:  Ardent Window Manager(X11), Part12/13
  5. Message-ID: <1636@wyse.wyse.com>
  6. Date: 12 Aug 88 15:24:32 GMT
  7. Sender: news@wyse.wyse.com
  8. Lines: 1474
  9. Approved: mikew@wyse.com
  10.  
  11. Submitted-by: unido!pcsbsd!jkh (Jordan Hubbard)
  12. Posting-number: Volume 0, Issue 13
  13. Archive-name: awm/part12
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 12 (of 13)."
  22. # Contents:  awm/awm.c
  23. # Wrapped by mikew@wyse on Mon Aug  8 12:01:48 1988
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f awm/awm.c -a "${1}" != "-c" ; then 
  26.   echo shar: Will not over-write existing file \"awm/awm.c\"
  27. else
  28. echo shar: Extracting \"awm/awm.c\" \(39402 characters\)
  29. sed "s/^X//" >awm/awm.c <<'END_OF_awm/awm.c'
  30. X#ident   "%W% %G%"
  31. X
  32. X
  33. X
  34. X#ifndef lint
  35. Xstatic char *rcsid_awm_c = "$Header: awm.c,v 1.4 88/07/24 01:24:56 jkh Exp $";
  36. X#endif  lint
  37. X
  38. X#include "X11/copyright.h"
  39. X/*
  40. X *
  41. X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
  42. X *
  43. X * Copyright 1987 by Jordan Hubbard.
  44. X *
  45. X *
  46. X *                         All Rights Reserved
  47. X *
  48. X * Permission to use, copy, modify, and distribute this software and its
  49. X * documentation for any purpose and without fee is hereby granted,
  50. X * provided that the above copyright notice appear in all copies and that
  51. X * both that copyright notice and this permission notice appear in
  52. X * supporting documentation, and that the name of Ardent Computer
  53. X * Corporation or Jordan Hubbard not be used in advertising or publicity
  54. X * pertaining to distribution of the software without specific, written
  55. X * prior permission.
  56. X *
  57. X */
  58. X
  59. X/*
  60. X * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  61. X *
  62. X *                         All Rights Reserved
  63. X *
  64. X * Permission to use, copy, modify, and distribute this software and its
  65. X * documentation for any purpose and without fee is hereby granted,
  66. X * provided that the above copyright notice appear in all copies and that
  67. X * both that copyright notice and this permission notice appear in
  68. X * supporting documentation, and that the name of Digital Equipment
  69. X * Corporation not be used in advertising or publicity pertaining to
  70. X * distribution of the software without specific, written prior permission.
  71. X *
  72. X *
  73. X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  74. X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  75. X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  76. X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  77. X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  78. X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  79. X * SOFTWARE.
  80. X */
  81. X
  82. X
  83. X/*
  84. X * MODIFICATION HISTORY
  85. X *
  86. X * 000 -- M. Gancarz, DEC Ultrix Engineering Group
  87. X * 001 -- Loretta Guarino Reid, DEC Ultrix Engineering Group,
  88. X *  Western Software Lab. Convert to X11.
  89. X * 002 -- Jordan Hubbard, U.C. Berkeley. Add title bar context stuff.
  90. X * 003 -- Jordan Hubbard, Ardent Computer. Added gadgets, border contexts.
  91. X */
  92. X
  93. X#include <sys/time.h>
  94. X#include <signal.h>
  95. X#if defined(vax)
  96. X#include <sys/file.h>
  97. X#else
  98. X#include <fcntl.h>
  99. X#endif /* vax */
  100. X#include <sys/ioctl.h>
  101. X#include "awm.h"
  102. X#include "X11/Xutil.h"
  103. X#include "X11/cursorfont.h"
  104. X
  105. X#ifdef PROFIL
  106. X#include <signal.h>
  107. X/*
  108. X * Dummy handler for profiling.
  109. X */
  110. Xptrap()
  111. X{
  112. X     exit(0);
  113. X}
  114. X#endif
  115. X
  116. XBoolean NeedRootInput=FALSE;
  117. XMenuOptionsMask options;
  118. Xchar *sfilename;
  119. Xchar execfile[NAME_LEN]; /* Pointer to file to exec with -e */
  120. XBoolean Snatched;
  121. XBoolean desktop_execd = TRUE;
  122. Xextern FILE *yyin;
  123. Xextern int errorStatus;
  124. Xextern int ErrorHandler();
  125. Xextern XContext AwmContext;
  126. X
  127. X/*
  128. X * Main program.
  129. X */
  130. Xmain(argc, argv, environ)
  131. Xint argc;
  132. Xchar **argv;
  133. Xchar **environ;
  134. X{
  135. X     int hi;            /* Button event high detail. */
  136. X     int lo;            /* Button event low detail. */
  137. X     int x, y;                  /* Mouse X and Y coordinates. */
  138. X     int root_x, root_y;        /* Mouse root X and Y coordinates. */
  139. X     int cur_x, cur_y;        /* Current mouse X and Y coordinates. */
  140. X     int down_x, down_y;    /* mouse X and Y at ButtonPress. */
  141. X     int str_width;             /* Width in pixels of output string. */
  142. X     int pop_width, pop_height; /* Pop up window width and height. */
  143. X     int context;        /* Root, window, or icon context. */
  144. X     int ptrmask;        /* for QueryPointer */
  145. X     Boolean func_stat;        /* If true, function swallowed a ButtonUp. */
  146. X     Boolean delta_done;    /* If true, then delta functions are done. */
  147. X     Boolean local;        /* If true, then do not use system defaults. */
  148. X     Boolean nolocal;        /* If true, ignore user defaults */
  149. X     register Binding *bptr;    /* Pointer to Bindings list. */
  150. X     char *root_name;        /* Root window name. */
  151. X     char *cp;            /* scratch */
  152. X     char *display = NULL;    /* Display name pointer. */
  153. X     char message[128];        /* Error message buffer. */
  154. X     char *rc_file;        /* Pointer to $HOME/.awmrc. */
  155. X     Window event_win;          /* Event window. */
  156. X     Window sub_win;        /* Subwindow for XUpdateMouse calls. */
  157. X     Window root;        /* Root window for QueryPointer. */
  158. X     XWindowAttributes event_info;/* Event window info. */
  159. X     AwmInfoPtr awi;
  160. X     XEvent button_event;     /* Button input event. */
  161. X     GC gc;            /* graphics context for gray background */
  162. X     XImage grayimage;        /* for gray background */
  163. X     XGCValues xgc;        /* to create font GCs */
  164. X     char *malloc();
  165. X     XSetWindowAttributes swa;
  166. X     unsigned long valuemask;
  167. X     Window bwin;        /* Button window */
  168. X     int num;
  169. X     
  170. X     /* next three variables are for XQueryWindow */
  171. X     Window junk;
  172. X     Window *kiddies;
  173. X     unsigned int nkids;
  174. X     
  175. X     Entry("main")
  176. X      
  177. X#ifdef PROFIL
  178. X      signal(SIGTERM, ptrap);
  179. X#endif
  180. X     
  181. X     /* 
  182. X      * Parse the command line arguments.
  183. X      */
  184. X     Argv = argv;
  185. X     Environ = environ;
  186. X     local = nolocal = FALSE;
  187. X     argc--, argv++;
  188. X     /*
  189. X      * The destruction of '-e' args below is to prevent the startup
  190. X      * command from being invoked again if we do an f.restart (see
  191. X      * Restart.c and Argv)
  192. X      */
  193. X     while (argc) {
  194. X      if (**argv == '-') {
  195. X           if (!strcmp(*argv, "-display") || !strcmp(*argv, "-d")) {
  196. X            argc--; argv++;
  197. X            if (argc <= 0)
  198. X             Usage();
  199. X            display = *argv;
  200. X           }
  201. X           else if (!(strcmp(*argv, "-f"))) {
  202. X            argc--, argv++;
  203. X            if ((argc == 0) || (Startup_File[0] != '\0'))
  204. X             Usage();
  205. X            strncpy(Startup_File, *argv, NAME_LEN);
  206. X           }
  207. X           else if (!(strcmp(*argv, "-e"))) {
  208. X            strcpy(*argv, "--");    /* destroy the arg */
  209. X            argc--; argv++;
  210. X            if ((argc == 0) || (execfile[0] != '\0'))
  211. X             Usage();
  212. X            desktop_execd = FALSE; /* assume we have desktop to run */
  213. X            strncpy(execfile, *argv, NAME_LEN);
  214. X           }
  215. X           /* Destroyed arg, skip over what used to be filename for -e */
  216. X           else if (!(strcmp(*argv, "--"))) {
  217. X            argv += 2; argc -= 2;
  218. X            continue;
  219. X           }
  220. X           else if (!(strcmp(*argv, "-b")))
  221. X            local = TRUE;
  222. X           else if (!(strcmp(*argv, "-i")))
  223. X            nolocal = TRUE;
  224. X           
  225. X           else Usage();
  226. X      }
  227. X      else
  228. X           Usage();
  229. X      argc--, argv++;
  230. X     }
  231. X#ifdef CONSOLE
  232. X     if (access("/dev/console", W_OK) == 0) {
  233. X          freopen("/dev/console", "w", stderr);
  234. X      freopen("/dev/console", "w", stdout);
  235. X     }
  236. X#endif /* CONSOLE */
  237. X     /* Open the damn display */
  238. X     if ((dpy = XOpenDisplay(display)) == NULL) {
  239. X      fprintf(stderr, "awm: Unable to open display\n");
  240. X      exit(1);
  241. X     }
  242. X
  243. X     scr = DefaultScreen(dpy);
  244. X     
  245. X     /*
  246. X      * Set XErrorFunction to be non-terminating.
  247. X      */
  248. X     XSetErrorHandler(ErrorHandler);
  249. X     
  250. X     /*
  251. X      * Force child processes to disinherit the TCP file descriptor.
  252. X      * This helps shell commands forked and exec'ed from menus
  253. X      * to work properly. God knows if this works under SysV.
  254. X      */
  255. X     if ((status = fcntl(ConnectionNumber(dpy), F_SETFD, 1)) == -1) {
  256. X      perror("awm: child cannot disinherit TCP fd");
  257. X      Error("TCP file descriptor problems");
  258. X     }
  259. X     
  260. X     /*
  261. X      * Initialize the menus for later use.
  262. X      */
  263. X     RTLMenu_Option_Set(options, rightoffset);
  264. X     RTLMenu_Initialize(options);
  265. X     
  266. X     /* Init the context manager stuff */
  267. X     AwmContext = XUniqueContext();
  268. X     
  269. X     /*
  270. X      * Get all the defaults we expect from the resource manager.
  271. X      */
  272. X     FocusSetByUser = FALSE;
  273. X     Get_Defaults();
  274. X     /*
  275. X      * Initialize the default bindings.
  276. X      */
  277. X     if (!local)
  278. X      InitBindings();
  279. X     
  280. X     /*
  281. X      * Read in and parse $HOME/.awmrc, if it exists.
  282. X      */
  283. X     if (!nolocal) {
  284. X      sfilename = rc_file = malloc(NAME_LEN);
  285. X      sprintf(rc_file, "%s/.awmrc", getenv("HOME"));
  286. X      if ((yyin = fopen(rc_file, "r")) != NULL) {
  287. X           Lineno = 1;
  288. X           yyparse();
  289. X           fclose(yyin);
  290. X           if (Startup_File_Error)
  291. X            Error("Bad .awmrc file...aborting");
  292. X      }
  293. X     }
  294. X     /* 
  295. X      * Read in and parse the startup file from the command line, if
  296. X      * specified.
  297. X      */
  298. X     if (Startup_File[0] != '\0') {
  299. X      sfilename = Startup_File;
  300. X      if ((yyin = fopen(Startup_File, "r")) == NULL) {
  301. X           sprintf(message, "Cannot open startup file '%s'", Startup_File);
  302. X           Error(message);
  303. X      }
  304. X      Lineno = 1;
  305. X      yyparse();
  306. X      fclose(yyin);
  307. X      if (Startup_File_Error)
  308. X           Error("Bad startup file...aborting");
  309. X     }
  310. X
  311. X     if (Startup_File_Error)
  312. X      Error("Bad startup file...aborting");
  313. X
  314. X     /*
  315. X      * Catch some of the basic signals so we don't get rudely killed without
  316. X      * cleaning up first.
  317. X      */
  318. X     signal(SIGHUP, Quit);
  319. X     signal(SIGTERM, Quit);
  320. X     signal(SIGQUIT, Quit);
  321. X     signal(SIGINT, Quit);
  322. X
  323. X     /*
  324. X      * If the root window has not been named, name it.
  325. X      */
  326. X     status = XFetchName(dpy, RootWindow(dpy, scr), &root_name);
  327. X     if (root_name == NULL) 
  328. X      XStoreName(dpy, RootWindow(dpy, scr), " X Root Window ");
  329. X     else
  330. X      free(root_name);
  331. X     /* register the root window */
  332. X     RegisterWindow(RootWindow(dpy, scr));
  333. X
  334. X     ScreenHeight = DisplayHeight(dpy, scr);
  335. X     ScreenWidth = DisplayWidth(dpy, scr);
  336. X
  337. X     /*
  338. X      * Create the menus. This function also sticks the RTL menu "handle"
  339. X      * into the appropriate binding after it's been created and initialized.
  340. X      */
  341. X     Create_Menus();
  342. X
  343. X     /*
  344. X      * check the gadgets.
  345. X      */
  346. X     if (CheckGadgets())
  347. X      Error("Error in gadget declarations. Exiting...\n");
  348. X
  349. X     /*
  350. X      * Store all the cursors.
  351. X      */
  352. X     StoreCursors();
  353. X     
  354. X     /* 
  355. X      * grab the mouse buttons according to the map structure
  356. X      */
  357. X     Grab_Buttons();
  358. X     
  359. X     /* 
  360. X      * watch for initial window mapping and window destruction
  361. X      */
  362. X     
  363. X     errorStatus = False;
  364. X     swa.event_mask = (SubstructureRedirectMask | FocusChangeMask |
  365. X               (NeedRootInput ? EVENTMASK |
  366. X            OwnerGrabButtonMask : 0));
  367. X     XChangeWindowAttributes(dpy, RootWindow(dpy, scr), CWEventMask, &swa);
  368. X     XSync(dpy, False);
  369. X     if (errorStatus)
  370. X      Error("Hmmm.. Looks like you're running another window manager!\n");
  371. X     /*
  372. X      * Before we go creating more windows, we buzz through the ones that
  373. X      * are currently mapped and reparent and/or select on them as necessary
  374. X      * (for autoraise and titles).
  375. X      */
  376. X     
  377. X     if (XQueryTree(dpy, DefaultRootWindow(dpy), &junk, &junk, &kiddies,
  378. X            &nkids) != BadWindow) {
  379. X      unsigned int i;
  380. X
  381. X      for (i = 0; i < nkids; i++) {
  382. X           XWindowAttributes xwa;
  383. X           Window transient;
  384. X           AwmInfoPtr awi;
  385. X           unsigned long event_mask;
  386. X           
  387. X           XGetWindowAttributes(dpy, kiddies[i], &xwa);
  388. X           
  389. X           /* check to see if it's a popup or something */
  390. X           XGetTransientForHint(dpy, kiddies[i], &transient);
  391. X           if (xwa.class == InputOutput && xwa.map_state == IsViewable &&
  392. X           xwa.override_redirect == False && transient == None) {
  393. X            awi = RegisterWindow(kiddies[i]);
  394. X            awi->state |= ST_PLACED;
  395. X            /* Possibly add a frame */
  396. X            FDecorate(kiddies[i]);
  397. X            event_mask = PropertyChangeMask | FocusChangeMask;
  398. X            if (!awi->frame || !FrameFocus)
  399. X             event_mask |= (EnterWindowMask | LeaveWindowMask);
  400. X            SetBorderPixmaps(dpy, kiddies[i], GrayPixmap);
  401. X            XSelectInput(dpy, kiddies[i], event_mask);
  402. X           }
  403. X      }
  404. X      XFree(kiddies);
  405. X     }
  406. X     /*
  407. X      * Calculate size of the resize pop-up window.
  408. X      */
  409. X     valuemask = CWBorderPixel | CWBackPixel;
  410. X     swa.border_pixel = PBorder;
  411. X     swa.background_pixel = PBackground;
  412. X     if (SaveUnder) {
  413. X      swa.save_under = True;
  414. X      valuemask |= CWSaveUnder;
  415. X     }
  416. X     str_width = XTextWidth(PFontInfo, PText, strlen(PText));
  417. X     pop_width = str_width + (PPadding << 1);
  418. X     PWidth = pop_width + (PBorderWidth << 1);
  419. X     pop_height = PFontInfo->ascent + PFontInfo->descent + (PPadding << 1);
  420. X     PHeight = pop_height + (PBorderWidth << 1);
  421. X     
  422. X     /*
  423. X      * Create the pop-up window.  Create it at (0, 0) for now.  We will
  424. X      * move it where we want later.
  425. X      */
  426. X     Pop = XCreateWindow(dpy, RootWindow(dpy, scr),
  427. X             0, 0,
  428. X             pop_width, pop_height,
  429. X             PBorderWidth,
  430. X             0,
  431. X             CopyFromParent,
  432. X             CopyFromParent,
  433. X             valuemask,
  434. X             &swa);
  435. X     if (Pop == FAILURE)
  436. X      Error("Can't create pop-up dimension display window.");
  437. X     
  438. X     /*
  439. X      * Create graphics context.
  440. X      */
  441. X     xgc.font = IFontInfo->fid;
  442. X     xgc.graphics_exposures = FALSE;
  443. X     xgc.foreground = IForeground;
  444. X     xgc.background = IBackground;
  445. X     IconGC = XCreateGC(dpy, 
  446. X            RootWindow(dpy, scr),
  447. X            (GCForeground | GCBackground | GCGraphicsExposures |
  448. X             GCFont), &xgc);
  449. X     
  450. X     xgc.foreground = PForeground;
  451. X     xgc.background = PBackground;
  452. X     xgc.font = PFontInfo->fid;
  453. X     PopGC = XCreateGC(dpy, 
  454. X               RootWindow(dpy, scr),
  455. X               (GCForeground | GCBackground | GCFont), &xgc);
  456. X     xgc.line_width = DRAW_WIDTH;
  457. X     xgc.foreground = DRAW_VALUE;
  458. X     xgc.function = DRAW_FUNC;
  459. X     xgc.subwindow_mode = IncludeInferiors;
  460. X     DrawGC = XCreateGC(dpy, RootWindow(dpy, scr), 
  461. X            GCLineWidth | GCForeground | GCFunction |
  462. X            GCSubwindowMode, &xgc);
  463. X
  464. X     /*
  465. X      * As our last "startup" task, invoke the execfile if was specified.
  466. X      */
  467. X     if (!desktop_execd) {
  468. X      if (access(execfile, X_OK) == 0) {
  469. X           if (fork() == 0) {
  470. X            setpgrp(0, 0);
  471. X            signal(SIGHUP, SIG_IGN);
  472. X            signal(SIGQUIT, SIG_IGN);
  473. X            signal(SIGINT, SIG_IGN);
  474. X            execl("/bin/sh", "sh", "-c", execfile, 0);
  475. X            _exit(127);
  476. X           }
  477. X           else
  478. X            desktop_execd = TRUE;
  479. X      }
  480. X     }
  481. X     /*
  482. X      * Tell the user we're alive and well.
  483. X      */
  484. X     XBell(dpy, VOLUME_PERCENTAGE(Volume));
  485. X     
  486. X     /* 
  487. X      * Main command loop.
  488. X      */
  489. X     while (TRUE) {
  490. X      
  491. X      delta_done = func_stat = FALSE;
  492. X      
  493. X      /*
  494. X       * Get the next mouse button event.  Spin our wheels until
  495. X       * a ButtonPressed event is returned.
  496. X       * Note that mouse events within an icon window are handled
  497. X       * in the "GetButton" function or by the icon's owner if
  498. X       * it is not awm.
  499. X       */
  500. X      while (TRUE) {
  501. X           if (!GetButton(&button_event))
  502. X            continue;
  503. X           else if (button_event.type == ButtonPress)
  504. X            break;
  505. X      }
  506. X      bwin = button_event.xbutton.window;
  507. X      /* save mouse coords in case we want them later for a delta action */
  508. X      down_x = button_event.xbutton.x;
  509. X      down_y = button_event.xbutton.y;
  510. X      
  511. X      /*
  512. X       * Okay, determine the event window and mouse coordinates.
  513. X       */
  514. X      status = XTranslateCoordinates(dpy, 
  515. X                     bwin,
  516. X                     RootWindow(dpy, scr),
  517. X                     button_event.xbutton.x, 
  518. X                     button_event.xbutton.y,
  519. X                     &x, &y,
  520. X                     &event_win);
  521. X      if (status == BadWindow)
  522. X           continue;
  523. X      
  524. X      awi = GetAwmInfo(bwin);
  525. X      if (!awi)
  526. X           continue;
  527. X
  528. X          if (awi->frame == bwin)
  529. X               context = BORDER;
  530. X      else if (awi->title == bwin)
  531. X           context = TITLE;
  532. X      else if (IsGadgetWin(bwin, &num))
  533. X           context = GADGET | (1 << (num + BITS_USED));
  534. X      else if (awi->icon == bwin)
  535. X           context = ICON;
  536. X      else if (awi->client == RootWindow(dpy, scr)) {
  537. X           event_win = RootWindow(dpy, scr);
  538. X           context = ROOT;
  539. X      }
  540. X      else
  541. X           context = WINDOW;
  542. X
  543. X      /*
  544. X       * Get the button event detail.
  545. X       */
  546. X      lo = button_event.xbutton.button;
  547. X      hi = button_event.xbutton.state;
  548. X      
  549. X      /*
  550. X       * Determine which function was selected and invoke it.
  551. X       */
  552. X      for(bptr = Blist; bptr; bptr = bptr->next) {
  553. X           if ((bptr->button != lo) ||
  554. X           (((int)bptr->mask & ModMask) != hi))
  555. X            continue;
  556. X           
  557. X           if ((bptr->context & context) != context) {
  558. X            continue;
  559. X               }
  560. X           if (!(bptr->mask & ButtonDown))
  561. X            continue;
  562. X           
  563. X           /*
  564. X        * Found a match! Invoke the function.
  565. X        */
  566. X           if ((*bptr->func)(event_win, (int)bptr->mask & ModMask,
  567. X                 bptr->button,
  568. X                 x, y,
  569. X                 bptr->menu, bptr->menuname))
  570. X            func_stat = TRUE;
  571. X           break;
  572. X      }
  573. X      
  574. X      /*
  575. X       * If the function ate the ButtonUp event, then restart the loop.
  576. X       */
  577. X      
  578. X      if (func_stat)
  579. X           continue;
  580. X      while (TRUE) {
  581. X           /*
  582. X        * Wait for the next button event.
  583. X        */
  584. X           if (XPending(dpy) && GetButton(&button_event)) {
  585. X            bwin = button_event.xbutton.window;
  586. X            /*
  587. X             * If it's not a release of button that was pressed,
  588. X             * don't do the function bound to 'ButtonUp'.
  589. X             */
  590. X            if (button_event.type != ButtonRelease)
  591. X             break;
  592. X            if (lo != button_event.xbutton.button)
  593. X             break;
  594. X            if ((hi | ButtonMask(lo)) != button_event.xbutton.state)
  595. X             break;
  596. X            /*
  597. X             * Okay, determine the event window and mouse coordinates.
  598. X             */
  599. X            status = XTranslateCoordinates(dpy, 
  600. X                           bwin,
  601. X                           RootWindow(dpy, scr),
  602. X                           button_event.xbutton.x,
  603. X                           button_event.xbutton.y,
  604. X                           &x, &y,
  605. X                           &event_win);
  606. X            if (status == BadWindow)
  607. X             break;
  608. X            awi = GetAwmInfo(bwin);
  609. X            if (!awi)
  610. X             continue;
  611. X            if (awi->frame == bwin)
  612. X             context = BORDER;
  613. X            else if (awi->title == bwin)
  614. X             context = TITLE;
  615. X            else if (IsGadgetWin(bwin, &num))
  616. X             context = GADGET | (1 << (num + BITS_USED));
  617. X            else if (awi->icon == bwin)
  618. X             context = ICON;
  619. X            else if (awi->client == RootWindow(dpy, scr)) {
  620. X             event_win = RootWindow(dpy, scr);
  621. X             context = ROOT;
  622. X            }
  623. X            else
  624. X             context = WINDOW;
  625. X            /*
  626. X             * Determine which function was selected and invoke it.
  627. X             */
  628. X            for(bptr = Blist; bptr; bptr = bptr->next) {
  629. X             
  630. X             if ((bptr->button != lo) ||
  631. X                 (((int)bptr->mask & ModMask) != hi))
  632. X                  continue;
  633. X             
  634. X             if (!((bptr->context & context) == context)) {
  635. X                  continue;
  636. X                         }
  637. X             
  638. X             if (!(bptr->mask & ButtonUp))
  639. X                  continue;
  640. X             
  641. X             /*
  642. X              * Found a match! Invoke the function.
  643. X              */
  644. X             
  645. X             (*bptr->func)(event_win,
  646. X                       (int)bptr->mask & ModMask,
  647. X                       bptr->button,
  648. X                       x, y,
  649. X                       bptr->menu, bptr->menuname);
  650. X             break;
  651. X            }
  652. X            break;
  653. X           }
  654. X           XQueryPointer(dpy, RootWindow(dpy, scr),
  655. X                 &root, &junk, &root_x, &root_y, &cur_x, &cur_y,
  656. X                 &ptrmask);
  657. X           if (!delta_done &&
  658. X           (abs(cur_x - x) > Delta || abs(cur_y - y) > Delta)) {
  659. X            /*
  660. X             * Delta functions are done once (and only once.)
  661. X             */
  662. X            delta_done = TRUE;
  663. X            
  664. X            /*
  665. X             * Determine the new event window's coordinates from the
  666. X             * original ButtonPress event.
  667. X             */
  668. X            status = XTranslateCoordinates(dpy, bwin,
  669. X                           RootWindow(dpy, scr),
  670. X                           down_x, down_y, &x, &y,
  671. X                           &junk);
  672. X            if (status == BadWindow)
  673. X             break;
  674. X
  675. X            /*
  676. X             * Determine the event window and context.
  677. X             */
  678. X            if (awi->frame == bwin)
  679. X             context = BORDER;
  680. X            else if (awi->title == bwin)
  681. X             context = TITLE;
  682. X            else if (IsGadgetWin(bwin, &num))
  683. X             context = GADGET | (1 << (num + BITS_USED));
  684. X            else if (awi->icon == bwin)
  685. X             context = ICON;
  686. X            else if (awi->client == RootWindow(dpy, scr)) {
  687. X             event_win = RootWindow(dpy, scr);
  688. X             context = ROOT;
  689. X            }
  690. X            else
  691. X             context = WINDOW;
  692. X            /*
  693. X             * Determine which function was selected and invoke it.
  694. X             */
  695. X            for(bptr = Blist; bptr; bptr = bptr->next) {
  696. X             
  697. X             if ((bptr->button != lo) ||
  698. X                 (((int)bptr->mask & ModMask) != hi))
  699. X                  continue;
  700. X             
  701. X             if (!((bptr->context & context) == context))
  702. X                  continue;
  703. X             
  704. X             if (!(bptr->mask & DeltaMotion))
  705. X                  continue;
  706. X             
  707. X             /*
  708. X              * Found a match! Invoke the function.
  709. X              */
  710. X             
  711. X             if ((*bptr->func)(event_win,
  712. X                       (int)bptr->mask & ModMask,
  713. X                       bptr->button,
  714. X                       x, y,
  715. X                       bptr->menu, bptr->menuname)) {
  716. X                  func_stat = TRUE;
  717. X                  break;
  718. X             }
  719. X            }
  720. X            /*
  721. X             * If the function ate the ButtonUp event,
  722. X             * then restart the loop.
  723. X             */
  724. X            
  725. X            if (func_stat)
  726. X             break;
  727. X           }
  728. X      }
  729. X     }
  730. X}
  731. X
  732. X/*
  733. X * Get defaults from the resource manager. Most of these things used to be
  734. X * in the rc file, but they really belong here, I think.
  735. X */
  736. XGet_Defaults()
  737. X{
  738. X     register char *cp;
  739. X     
  740. X     /*
  741. X      * Get the pixmap search path, if it exists.
  742. X      */
  743. X     awmPath = GetStringRes("path", NULL);
  744. X
  745. X     /* Default foreground/background colors (text) */
  746. X     Foreground = GetStringRes("foreground", "black");
  747. X     Background = GetStringRes("background", "white");
  748. X     
  749. X     if (Reverse) { /* Swap the foreground and background */
  750. X      char *tmp;
  751. X      
  752. X      tmp = Foreground;
  753. X      Foreground = Background;
  754. X          Background = tmp;
  755. X     }
  756. X     WBorder = GetStringRes("border.foreground", Foreground);
  757. X     
  758. X     Autoselect = GetBoolRes("autoselect", FALSE);
  759. X     Autoraise = GetBoolRes("autoraise", FALSE);
  760. X     Borders = GetBoolRes("borderContexts", FALSE);
  761. X     ConstrainResize = GetBoolRes("constrainResize", FALSE);
  762. X     FrameFocus = GetBoolRes("frameFocus", FALSE);
  763. X     Freeze = GetBoolRes("freeze", FALSE);
  764. X     Grid = GetBoolRes("grid", FALSE);
  765. X     InstallColormap = GetBoolRes("installColormap", FALSE);
  766. X     Titles = GetBoolRes("titles", FALSE);
  767. X     PushDown = GetBoolRes("title.push", FALSE);
  768. X     UseGadgets = GetBoolRes("gadgets", FALSE);
  769. X     Hilite = GetBoolRes("hilite", FALSE);
  770. X     BorderHilite = GetBoolRes("border.hilite", Hilite);
  771. X     RootResizeBox = GetBoolRes("rootResizeBox", FALSE);
  772. X     ResizeRelative = GetBoolRes("resizeRelative", FALSE);
  773. X     NIcon = GetBoolRes("normali", TRUE);
  774. X     ShowName = GetBoolRes("showName", TRUE);
  775. X     NWindow = GetBoolRes("normalw", TRUE);
  776. X     Push = GetBoolRes("pushRelative", FALSE);
  777. X     Reverse = GetBoolRes("reverse", FALSE);
  778. X     SaveUnder = GetBoolRes("saveUnder", FALSE);
  779. X     Wall = GetBoolRes("wall", FALSE);
  780. X     WarpOnRaise = GetBoolRes("warpOnRaise", FALSE);
  781. X     WarpOnIconify = GetBoolRes("warpOnIconify", FALSE);
  782. X     WarpOnDeIconify = GetBoolRes("warpOnDeIconify", FALSE);
  783. X     Zap = GetBoolRes("zap", FALSE);
  784. X     
  785. X     HIconPad = GetIntRes("icon.hPad", DEF_ICON_PAD);
  786. X     VIconPad = GetIntRes("icon.vPad", DEF_ICON_PAD);
  787. X     RaiseDelay = GetIntRes("raiseDelay", DEF_RAISE_DELAY);
  788. X     PBorderWidth = GetIntRes("popup.borderWidth", DEF_POP_BORDER_WIDTH);
  789. X     IBorderWidth = GetIntRes("icon.borderWidth", DEF_ICON_BORDER_WIDTH);
  790. X     PPadding = GetIntRes("popup.pad", DEF_POP_PAD);
  791. X     MBorderWidth = GetIntRes("menu.borderWidth", DEF_MENU_BORDER_WIDTH);
  792. X     MItemBorder = GetIntRes("menu.itemBorder", 1);
  793. X     MDelta = GetIntRes("menu.delta", DEF_MENU_DELTA);
  794. X     MPad = GetIntRes("menu.pad", DEF_MENU_PAD);
  795. X     Delta = GetIntRes("delta", DEF_DELTA);
  796. X     Volume = GetIntRes("volume", DEF_VOLUME);
  797. X     Pushval = GetIntRes("push", DEF_PUSH);
  798. X     BContext = GetIntRes("borderContext.width", DEF_BCONTEXT_WIDTH);
  799. X
  800. X     ForeColor = GetColorRes("foreground", BlackPixel(dpy, scr));
  801. X     BackColor = GetColorRes("background", WhitePixel(dpy, scr));
  802. X     IForeground = GetColorRes("icon.foreground", ForeColor);
  803. X     IBackground = GetColorRes("icon.background", BackColor);
  804. X     IBorder = GetColorRes("icon.border", IForeground);
  805. X     ITextForeground = GetColorRes("icon.text.foreground", IForeground);
  806. X     ITextBackground = GetColorRes("icon.text.background", IBackground);
  807. X     PBorder = GetColorRes("popup.border", ForeColor);
  808. X     PForeground = GetColorRes("popup.foreground", PBorder);
  809. X     PBackground = GetColorRes("popup.background", BackColor);
  810. X     MForeground = GetColorRes("menu.foreground", ForeColor);
  811. X     MBackground = GetColorRes("menu.background", BackColor);
  812. X     MBorder = GetColorRes("menu.border", MForeground);
  813. X
  814. X     /*
  815. X      * Create and store the grey and solid pixmaps
  816. X      */
  817. X     GrayPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
  818. X                          gray_bits,
  819. X                          gray_width, gray_height,
  820. X                          ForeColor,
  821. X                          BackColor,
  822. X                          DefaultDepth(dpy, scr));
  823. X
  824. X     SolidPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
  825. X                           solid_bits,
  826. X                           solid_width, solid_height,
  827. X                           ForeColor,
  828. X                           BackColor,
  829. X                           DefaultDepth(dpy, scr));
  830. X
  831. X     IFontInfo = GetFontRes("icon.font", DEF_ICON_FONT);
  832. X     PFontInfo = GetFontRes("popup.font", DEF_POPUP_FONT);
  833. X     MFontInfo = GetFontRes("menu.font", DEF_MENU_FONT);
  834. X     MBoldFontInfo = GetFontRes("menu.boldFont", DEF_BOLD_FONT);
  835. X
  836. X     
  837. X     IBackPixmap = GetPixmapRes("icon.pixmap", GrayPixmap, IForeground,
  838. X                IBackground);
  839. X     
  840. X#ifdef NEATEN
  841. X     AbsMinWidth = GetIntRes("neaten.absMinWidth", DEFAULT_ABS_MIN);
  842. X     AbsMinHeight = GetIntRes("neaten.absMinHeight", DEFAULT_ABS_MIN);
  843. X     
  844. X     RetainSize = GetBoolRes("neaten.retainSize", TRUE);
  845. X     KeepOpen = GetBoolRes("neaten.keepOpen", TRUE);
  846. X     Fill = GetBoolRes("neaten.fill", TRUE);
  847. X     UsePriorities = GetBoolRes("neaten.usePriorities", TRUE);
  848. X     FixTopOfStack = GetBoolRes("neaten.fixTopOfStack", TRUE);
  849. X     
  850. X     PrimaryIconPlacement = GetStringRes("neaten.primaryIconPlacement",
  851. X                     DEF_PRIMARY_PLACEMENT);
  852. X     SecondaryIconPlacement = GetStringRes("neaten.secondaryIconPlacement",
  853. X                       DEF_SECONDARY_PLACEMENT);
  854. X#endif
  855. X     
  856. X     Leave_void
  857. X}
  858. X
  859. X/*
  860. X * Look up string resource "string". If undefined, return "def_val"
  861. X */
  862. Xchar *GetStringRes(string, def_val)
  863. Xchar *string, *def_val;
  864. X{
  865. X     char *cp;
  866. X     
  867. X     Entry("GetStringRes")
  868. X     
  869. X     if ((cp = XGetDefault(dpy, NAME, string)) ||
  870. X     (cp = XGetDefault(dpy, CLASS, string))) {
  871. X      if (!strlen(cp))
  872. X           Leave(def_val)
  873. X      else
  874. X           Leave(cp)
  875. X     }
  876. X     Leave(def_val)
  877. X}
  878. X
  879. X/*
  880. X * Look up boolean resource "string". If undefined, return "def_val"
  881. X */
  882. XBoolean GetBoolRes(string, def_val)
  883. Xchar *string;
  884. XBoolean def_val;
  885. X{
  886. X     char *cp;
  887. X     
  888. X     Entry("GetBoolRes")
  889. X     
  890. X     if ((cp = XGetDefault(dpy, NAME, string)) ||
  891. X     (cp = XGetDefault(dpy, CLASS, string)))
  892. X      if (Pred(cp) > 0)
  893. X        def_val = TRUE;
  894. X     Leave(def_val)
  895. X}
  896. X
  897. X/*
  898. X * Look up integer resource "string". If undefined or non-numeric,
  899. X * return def_val.
  900. X */
  901. Xint GetIntRes(string, def_val)
  902. Xchar *string;
  903. Xint def_val;
  904. X{
  905. X     char *cp;
  906. X     
  907. X     Entry("GetIntRes")
  908. X     
  909. X     if ((cp = XGetDefault(dpy, NAME, string)) ||
  910. X     (cp = XGetDefault(dpy, CLASS, string))) {
  911. X      if (!strlen(cp) || !((*cp >= '0' && *cp <= '9') || *cp == '-'))
  912. X           Leave(def_val)
  913. X      Leave(atoi(cp))
  914. X     }
  915. X     Leave(def_val)
  916. X}
  917. X
  918. X/*
  919. X * Try to load pixmap file named by resource "string". Return 0 if
  920. X * unsuccessful. Otherwise, set width, height and return data.
  921. X */
  922. Xchar *GetPixmapDataRes(string, wide, high)
  923. Xchar *string;
  924. Xint *wide, *high;
  925. X{
  926. X     char *cp, *cp2;
  927. X     
  928. X     Entry("GetPixmapDataRes")
  929. X     
  930. X     if ((cp = XGetDefault(dpy, NAME, string)) ||
  931. X     (cp = XGetDefault(dpy, CLASS, string))) {
  932. X      char *data;
  933. X      int junk;
  934. X      
  935. X      cp2 = expand_from_path(cp);
  936. X      if (!cp2) {
  937. X           fprintf(stderr, "awm: Can't find pixmap file '%s' for '%s'\n",
  938. X               cp, string);
  939. X           Leave(0)
  940. X      }
  941. X      if (XReadBitmapFileData(cp2, wide, high, &data, &junk, &junk)
  942. X          != BitmapSuccess) {
  943. X           fprintf(stderr, "awm: Can't read pixmap file '%s' for '%s'.\n",
  944. X               cp, string);
  945. X      }
  946. X      else {
  947. X           Leave(data)
  948. X      }
  949. X     }
  950. X     Leave(0)
  951. X}
  952. X
  953. X/*
  954. X * Try to allocate pixmap resources named by "string", return "def_pix"
  955. X * if not found.
  956. X */
  957. XPixmap GetPixmapRes(string, def_pix, fg, bg)
  958. Xchar *string;
  959. XPixmap def_pix;
  960. XPixel fg, bg;
  961. X{
  962. X     char *data;
  963. X     Pixmap tmp;
  964. X     int wide, high;
  965. X
  966. X     Entry("GetPixmapRes")
  967. X
  968. X     if (data = GetPixmapDataRes(string, &wide, &high)) {
  969. X      tmp = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
  970. X                        data, wide, high, fg, bg,
  971. X                        DefaultDepth(dpy, scr));
  972. X      XFree(data);
  973. X      if (!tmp) {
  974. X           fprintf(stderr,
  975. X               "awm: Can't create pixmap '%s', using default.\n",
  976. X               string);
  977. X           tmp = def_pix;
  978. X      }
  979. X     }
  980. X     else
  981. X      tmp = def_pix;
  982. X     Leave(tmp)
  983. X     }
  984. X
  985. X/*
  986. X * Try to allocate color resource named by "string", return "color"
  987. X * if not found.This routine is only used for allocating colors from
  988. X * the default colormap.
  989. X */
  990. XPixel GetColorRes(string, color)
  991. Xchar *string;
  992. XPixel color;
  993. X{
  994. X     char *cp;
  995. X     Pixel tmp_color;
  996. X     Boolean status;
  997. X     
  998. X     Entry("GetColorRes")
  999. X     
  1000. X     if ((cp = XGetDefault(dpy, NAME, string)) ||
  1001. X     (cp = XGetDefault(dpy, CLASS, string))) {
  1002. X      tmp_color = LookupColor(cp, DefaultColormap(dpy, scr), &status);
  1003. X      if (!status) /* lookup succeeded */
  1004. X           Leave(tmp_color)
  1005. X      else
  1006. X           tmp_color = color;
  1007. X     }
  1008. X     else
  1009. X      tmp_color = color;
  1010. X     Leave(tmp_color)
  1011. X}
  1012. X
  1013. X/*
  1014. X * Try and get font resource "string", using "default" if not found. If
  1015. X * neither are available, use server default.
  1016. X */
  1017. X
  1018. XXFontStruct *GetFontRes(string, dflt)
  1019. Xchar *string, *dflt;
  1020. X{
  1021. X     char *cp;
  1022. X     XFontStruct *tmp;
  1023. X     static XFontStruct *def_font = 0;
  1024. X     
  1025. X     Entry("GetFontRes")
  1026. X     
  1027. X     if (!def_font)
  1028. X      def_font = XLoadQueryFont(dpy, DEF_FONT);
  1029. X     
  1030. X     if ((cp = XGetDefault(dpy, NAME, string)) ||
  1031. X     (cp = XGetDefault(dpy, CLASS, string))) {
  1032. X      if (tmp = XLoadQueryFont(dpy, cp))
  1033. X           Leave(tmp)
  1034. X      else
  1035. X           fprintf(stderr, "awm: Can't load %s '%s', trying '%s'.\n",
  1036. X               string, cp, dflt);
  1037. X     }
  1038. X     if (!dflt) /* NULL means we're not supposed to try again */
  1039. X      Leave(NULL)
  1040. X     if (tmp = XLoadQueryFont(dpy, dflt))
  1041. X      Leave(tmp)
  1042. X     else
  1043. X      fprintf(stderr, "awm: Can't open default font '%s', using server default.\n", dflt);
  1044. X     Leave(def_font)
  1045. X}
  1046. X
  1047. XAwmInfoPtr GetAwmInfo(w)
  1048. XWindow w;
  1049. X{
  1050. X     static AwmInfoPtr tmp;
  1051. X     
  1052. X     Entry("GetAwmInfo")
  1053. X     
  1054. X     if (!XFindContext(dpy, w, AwmContext, &tmp))
  1055. X      Leave(tmp)
  1056. X     else
  1057. X      Leave((AwmInfoPtr)NULL)
  1058. X}
  1059. X
  1060. XAwmInfoPtr RegisterWindow(w)
  1061. XWindow w;
  1062. X{
  1063. X     AwmInfoPtr tmp;
  1064. X     XClassHint clh;
  1065. X     XWMHints *wm_hints;
  1066. X     char *cp;
  1067. X
  1068. X     Entry("RegisterWindow")
  1069. X     
  1070. X     tmp = (AwmInfoPtr)malloc(sizeof(AwmInfo));
  1071. X     tmp->client = w;
  1072. X     tmp->title = tmp->frame = tmp->icon = (Window)0;
  1073. X     tmp->gadgets = (Window *)0;
  1074. X     tmp->name = (char *)0;
  1075. X     tmp->own = (Boolean)FALSE;
  1076. X     tmp->back = tmp->bold = tmp->BC_back = tmp->BC_bold =
  1077. X      tmp->iconPixmap = (Pixmap)0;
  1078. X     tmp->state = ST_WINDOW;
  1079. X     tmp->winGC = XCreateGC(dpy, w, (unsigned long)0, 0);
  1080. X     /*
  1081. X      * Determine attribute set by first turning on all attributes
  1082. X      * that are set by booleans and then (possibly) override them
  1083. X      * by checking to see what an individual window might want.
  1084. X      */
  1085. X     tmp->attrs = AT_NONE;
  1086. X     if (Titles)
  1087. X      tmp->attrs |= AT_TITLE;
  1088. X     if (UseGadgets)
  1089. X      tmp->attrs |= AT_GADGETS;
  1090. X     if (Borders)
  1091. X      tmp->attrs |= AT_BORDER;
  1092. X     if (Autoraise)
  1093. X      tmp->attrs |= AT_RAISE;
  1094. X     if (wm_hints = XGetWMHints(dpy, w)) {
  1095. X      if (wm_hints->input)
  1096. X             tmp->attrs |= AT_INPUT;
  1097. X      XFree(wm_hints);
  1098. X     }
  1099. X     clh.res_name = clh.res_class = (char *)NULL;
  1100. X     XGetClassHint(dpy, w, &clh);
  1101. X     if (clh.res_class) {
  1102. X      if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.title")))
  1103. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_TITLE, Pred(cp));
  1104. X      
  1105. X      if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.gadgets")))
  1106. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_GADGETS, Pred(cp));
  1107. X
  1108. X      if (cp = (XGetDefault(dpy, clh.res_class,"wm_option.borderContext")))
  1109. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_BORDER, Pred(cp));
  1110. X
  1111. X      if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.autoRaise")))
  1112. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_RAISE, Pred(cp));
  1113. X     }
  1114. X     if (clh.res_name) {
  1115. X      if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.title")))
  1116. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_TITLE, Pred(cp));
  1117. X      
  1118. X      if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.gadgets")))
  1119. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_GADGETS, Pred(cp));
  1120. X
  1121. X      if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.borderContext")))
  1122. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_BORDER, Pred(cp));
  1123. X
  1124. X      if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.autoRaise")))
  1125. X           tmp->attrs = SetOptFlag(tmp->attrs, AT_RAISE, Pred(cp));
  1126. X     }
  1127. X     XSaveContext(dpy, w, AwmContext, tmp);
  1128. X     Leave(tmp)
  1129. X}
  1130. X
  1131. X/*
  1132. X * Sets bit "flag" conditionally, based on state of "mask" and
  1133. X * "predicate" (mask denotes current state, predicate denotes
  1134. X * whether change is desired).
  1135. X */
  1136. Xint SetOptFlag(mask, flag, predicate)
  1137. Xint mask, flag, predicate;
  1138. X{
  1139. X     Entry("SetOptFlag")
  1140. X
  1141. X     switch (predicate) {
  1142. X     case -1:
  1143. X      Leave(mask)
  1144. X          break;
  1145. X
  1146. X     case 0:
  1147. X          if (mask & flag)
  1148. X           Leave(mask ^ flag)
  1149. X          else
  1150. X           Leave(mask)
  1151. X      break;
  1152. X
  1153. X     case 1:
  1154. X      Leave(mask | flag)
  1155. X      break;
  1156. X     }
  1157. X}
  1158. X
  1159. X/*
  1160. X * check whether a string denotes an "on" or "off" value. Return 0
  1161. X * if "off", 1 if "on" and -1 if undefined (or null).
  1162. X */
  1163. XPred(s)
  1164. Xchar *s;
  1165. X{
  1166. X     int i, len;
  1167. X     char *tmp;
  1168. X     Boolean ret = -1;
  1169. X     Entry("Pred")
  1170. X
  1171. X     if (!s)
  1172. X      Leave(-1)
  1173. X     len = strlen(s);
  1174. X     if (!len)
  1175. X      Leave(-1)
  1176. X     tmp = (char *)malloc(len + 1);
  1177. X     if (!tmp) {
  1178. X      fprintf(stderr, "awm: Pred: Can't allocate storage for '%s'!\n", s);
  1179. X      Leave(-1)
  1180. X     }
  1181. X     strcpy(tmp, s);
  1182. X     for (i = 0; i < len; i++)
  1183. X      if (tmp[i] >= 'A' && tmp[i] <= 'Z')
  1184. X           tmp[i] += 32;
  1185. X     if (*tmp == 'y' || !strcmp(tmp, "on")
  1186. X     || !strcmp(tmp, "true")
  1187. X     || !strcmp(tmp, "enable"))
  1188. X      ret = 1;
  1189. X     else if (*tmp == 'n' || !strcmp(tmp, "off")
  1190. X          || !strcmp(tmp, "false")
  1191. X          || !strcmp(tmp, "disable"))
  1192. X      ret = 0;
  1193. X     free(tmp);
  1194. X     Leave(ret)
  1195. X}
  1196. X
  1197. X/*
  1198. X * Initialize the default bindings.  First, write the character array
  1199. X * out to a temp file, then point the parser to it and read it in.
  1200. X * Afterwards, we unlink the temp file.
  1201. X */
  1202. XInitBindings()
  1203. X{
  1204. X     char *mktemp();
  1205. X     char *tempfile;
  1206. X     register FILE *fp;        /* Temporary file pointer. */
  1207. X     register char **ptr;    /* Default bindings string array pointer. */
  1208. X     
  1209. X     Entry("InitBindings")
  1210. X     
  1211. X     /*
  1212. X      * Create and write the temp file.
  1213. X      */
  1214. X     /*
  1215. X      * This used to just call mktemp() on TEMPFILE, which was very
  1216. X      * evil as it involved writing on a string constant. This extra
  1217. X      * mastication is necessary to prevent that.
  1218. X      */
  1219. X     tempfile = (char *)malloc(strlen(TEMPFILE) + 1);
  1220. X     strcpy(tempfile, TEMPFILE);
  1221. X     sfilename = mktemp(tempfile);
  1222. X     if ((fp = fopen(tempfile, "w")) == NULL) {
  1223. X      perror("awm: cannot create temp file");
  1224. X      exit(1);
  1225. X     }
  1226. X     for (ptr = DefaultBindings; *ptr; ptr++) {
  1227. X      fputs(*ptr, fp);
  1228. X      fputc('\n', fp);
  1229. X     }
  1230. X     fclose(fp);
  1231. X     
  1232. X     /*
  1233. X      * Read in the bindings from the temp file and parse them.
  1234. X      */
  1235. X     if ((yyin = fopen(tempfile, "r")) == NULL) {
  1236. X      perror("awm: cannot open temp file");
  1237. X      exit(1);
  1238. X     }
  1239. X     Lineno = 1;
  1240. X     yyparse();
  1241. X     fclose(yyin);
  1242. X     unlink(tempfile);
  1243. X     free(tempfile);
  1244. X     if (Startup_File_Error)
  1245. X      Error("Bad default bindings...aborting");
  1246. X     
  1247. X     /*
  1248. X      * Parse the system startup file, if one exists.
  1249. X      */
  1250. X     if ((yyin = fopen(SYSFILE, "r")) != NULL) {
  1251. X      sfilename = SYSFILE;
  1252. X      Lineno = 1;
  1253. X      yyparse();
  1254. X      fclose(yyin);
  1255. X      if (Startup_File_Error)
  1256. X           Error("Bad system startup file...aborting");
  1257. X     }
  1258. X     Leave_void
  1259. X}
  1260. X
  1261. X/*
  1262. X * Create the menus and alter any appropriate bindings so that the RTL menu
  1263. X * handle is passed along in subsequent actions.
  1264. X */
  1265. XCreate_Menus()
  1266. X{
  1267. X     Binding *bptr;
  1268. X     MenuInfo *minfo;
  1269. X     MenuLink *lnk;
  1270. X     
  1271. X     Entry("Create_Menus")
  1272. X     
  1273. X     /*
  1274. X      * We start with the bindings list because we don't want to bother
  1275. X      * creating a menu that's been declared but not referenced.
  1276. X      */
  1277. X     for(bptr = Blist; bptr; bptr = bptr->next) {
  1278. X      if (bptr->func == DoMenu) {
  1279. X           if (minfo = (MenuInfo *)FindMenu(bptr->menuname))
  1280. X            bptr->menu = (RTLMenu)create_menu(minfo);
  1281. X           else {
  1282. X            fprintf(stderr, "awm: non-existent menu reference: \"%s\"\n",
  1283. X                bptr->menuname);
  1284. X            Startup_File_Error = TRUE;
  1285. X           }
  1286. X      }
  1287. X     }
  1288. X     for (lnk = Menus; lnk; lnk = lnk->next) {
  1289. X      free(lnk->menu);
  1290. X      free(lnk);
  1291. X     }
  1292. X     Leave_void
  1293. X}
  1294. X
  1295. X/*
  1296. X * Grab the mouse buttons according to the bindings list.
  1297. X */
  1298. X
  1299. XGrab_Buttons()
  1300. X{
  1301. X     Binding *bptr;
  1302. X     
  1303. X     Entry("Grab_Buttons")
  1304. X     
  1305. X     /*
  1306. X      * don't grab buttons if you don't have to - allow application
  1307. X      * access to buttons unless context includes window.
  1308. X      */
  1309. X     for (bptr = Blist; bptr; bptr = bptr->next) {
  1310. X      if (bptr->context == ROOT)
  1311. X           NeedRootInput = TRUE;
  1312. X      else if (bptr->context & WINDOW) /* We gotta grab on windows */
  1313. X           GrabAll(bptr->mask);
  1314. X     }
  1315. X     Leave_void
  1316. X}
  1317. X
  1318. X/*
  1319. X * Register a grab on all windows in the hierarchy. This is better than
  1320. X * registering a grab on the RootWindow since it leaves button/key chords
  1321. X * available for other contexts.
  1322. X */
  1323. XGrabAll(mask)
  1324. Xunsigned int mask;
  1325. X{
  1326. X     int junk, nkids;
  1327. X     Window *kiddies;
  1328. X     
  1329. X     Entry("GrabAll")
  1330. X     
  1331. X     if (XQueryTree(dpy, DefaultRootWindow(dpy), &junk, &junk, &kiddies, &nkids)
  1332. X     != BadWindow) {
  1333. X      unsigned int i;
  1334. X      
  1335. X      for (i = 0; i < nkids; i++) {
  1336. X           Window transient;
  1337. X           XWindowAttributes xwa;
  1338. X           
  1339. X           /* check to see if it's a popup or something */
  1340. X           XGetWindowAttributes(dpy, kiddies[i], &xwa);
  1341. X           XGetTransientForHint(dpy, kiddies[i], &transient);
  1342. X           if (xwa.class == InputOutput && xwa.map_state == IsViewable &&
  1343. X           xwa.override_redirect == False && transient == None)
  1344. X            Grab(mask, kiddies[i]);
  1345. X      }
  1346. X     }
  1347. X     else
  1348. X      Error("awm: Can't XQueryTree in GrabAll!\n");
  1349. X     Leave_void
  1350. X}
  1351. X
  1352. X/*
  1353. X * Grab a mouse button according to the given mask.
  1354. X */
  1355. XGrab(mask, w)
  1356. Xunsigned int mask;
  1357. XWindow w;
  1358. X{
  1359. X     unsigned int m = LeftMask | MiddleMask | RightMask;
  1360. X     
  1361. X     Entry("Grab")
  1362. X     
  1363. X     switch (mask & m) {
  1364. X     case LeftMask:
  1365. X      XGrabButton(dpy, LeftButton, mask & ModMask, w, TRUE, EVENTMASK,
  1366. X              GrabModeAsync, GrabModeAsync, None, LeftButtonCursor);
  1367. X      break;
  1368. X      
  1369. X     case MiddleMask:
  1370. X      XGrabButton(dpy, MiddleButton, mask & ModMask, w, TRUE, EVENTMASK,
  1371. X              GrabModeAsync, GrabModeAsync, None, MiddleButtonCursor);
  1372. X      break;
  1373. X      
  1374. X     case RightMask:
  1375. X      XGrabButton(dpy, RightButton, mask & ModMask, w, TRUE, EVENTMASK,
  1376. X              GrabModeAsync, GrabModeAsync, None, RightButtonCursor);
  1377. X      break;
  1378. X     }
  1379. X     Leave_void
  1380. X}
  1381. X
  1382. X/*
  1383. X * Restore cursor to normal state.
  1384. X */
  1385. XResetCursor(button)
  1386. Xint button;
  1387. X{
  1388. X     Entry("ResetCursor")
  1389. X     
  1390. X     switch (button) {
  1391. X     case LeftButton:
  1392. X      XChangeActivePointerGrab(dpy, EVENTMASK, LeftButtonCursor,
  1393. X                   CurrentTime);
  1394. X      break;
  1395. X      
  1396. X     case MiddleButton:
  1397. X      XChangeActivePointerGrab(dpy, EVENTMASK, MiddleButtonCursor,
  1398. X                   CurrentTime);
  1399. X      break;
  1400. X      
  1401. X     case RightButton:
  1402. X      XChangeActivePointerGrab(dpy, EVENTMASK, RightButtonCursor,
  1403. X                   CurrentTime);
  1404. X      break;
  1405. X     }
  1406. X     Leave_void
  1407. X}
  1408. X
  1409. X/*
  1410. X * error routine for .awmrc parser
  1411. X */
  1412. Xyyerror(s)
  1413. Xchar*s;
  1414. X{
  1415. X     Entry("yyerror")
  1416. X     
  1417. X     fprintf(stderr, "awm: %s: Line %d: %s\n", sfilename, Lineno, s);
  1418. X     Startup_File_Error = TRUE;
  1419. X     Leave_void
  1420. X}
  1421. X
  1422. X/*
  1423. X * warning routine for .awmrc parser
  1424. X */
  1425. Xyywarn(s)
  1426. Xchar*s;
  1427. X{
  1428. X     Entry("yywarn")
  1429. X     
  1430. X     fprintf(stderr, "awm: Warning: %s: Line %d: %s\n", sfilename, Lineno, s);
  1431. X     Leave_void
  1432. X}
  1433. X
  1434. X/*
  1435. X * Print usage message and quit.
  1436. X */
  1437. XUsage()
  1438. X{
  1439. X     Entry("Usage")
  1440. X     
  1441. X     fputs("Usage: awm [-b] [-i] [-f <file>] [-e <file>] [<host>:<display>]\n\n",
  1442. X       stderr);
  1443. X     fputs("The -b option bypasses system and default bindings\n", stderr);
  1444. X     fputs("The -i option ignores the $HOME/.awmrc file\n", stderr);
  1445. X     fputs("The -f option specifies an alternate startup file\n", stderr);
  1446. X     fputs("The -e option specifies a program/script to exec after startup\n",
  1447. X       stderr);
  1448. X     exit(1);
  1449. X}
  1450. X
  1451. X/*
  1452. X * error handler for X I/O errors
  1453. X */
  1454. XXIOError(dsp)
  1455. XDisplay *dsp;
  1456. X{
  1457. X     /* perror("awm"); */
  1458. X     exit(3);
  1459. X}
  1460. END_OF_awm/awm.c
  1461. if test 39402 -ne `wc -c <awm/awm.c`; then
  1462.     echo shar: \"awm/awm.c\" unpacked with wrong size!
  1463. fi
  1464. # end of overwriting check
  1465. fi
  1466. echo shar: End of archive 12 \(of 13\).
  1467. cp /dev/null ark12isdone
  1468. MISSING=""
  1469. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1470.     if test ! -f ark${I}isdone ; then
  1471.     MISSING="${MISSING} ${I}"
  1472.     fi
  1473. done
  1474. if test "${MISSING}" = "" ; then
  1475.     echo You have unpacked all 13 archives.
  1476.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1477. else
  1478.     echo You still need to unpack the following archives:
  1479.     echo "        " ${MISSING}
  1480. fi
  1481. ##  End of shell archive.
  1482. exit 0
  1483. Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330
  1484.